01. model train (2)

python
pytorch
BP
Author

GC

Published

December 28, 2023

- environment : local jupyter lab

- 앞에서 주어진 데이터로 모델을 돌려봤으니까 이제 우리 데이터로 모델을 학습하고 돌려보자.

import

Code
#!pip install pafy youtube-dl moviepy
#!pip install pytube
#!pip install opencv-python

import random
import time
import math
import numpy as np
import torch
import os
import cv2
import torchvision
from moviepy.editor import *
from collections import deque
import sys

- 경로 추가

  • 경로 추가해도 안되니 걍 해당 파일을 현재 작업 경로에 넣어 두자

- 사용자 정의 .py 파일 import

  • 아래 패키지 설치하고 커널 restart
#!pip install --user albumentations
import Fight_utils
from Fight_utils import *

Fine Tuning and Training

Code
seed_constant = 70
np.random.seed(seed_constant)
random.seed(seed_constant)
torch.manual_seed(seed_constant)
torch.cuda.manual_seed_all(seed_constant)

사전학습된 모델 로드

model_ft = torchvision.models.video.mc3_18(pretrained=True, progress=True)

- 인풋, 아웃풋 피처별 선형 레이어 생성

num_ftrs = model_ft.fc.in_features   #
model_ft.fc = torch.nn.Linear(num_ftrs, 2) #nn.Linear(in_features, out_features)

샘플 데이터셋 로드

- 일단 임의로 넣어둔 20개 데이터로만 학습하자.

- 흠…로컬에서는 경로 설정이 조금 빡세다….

DATASET_DIR = 'D:\projects\mysite2\posts\DX\BP\Fight_Detection_From_Surveillance_Cameras-PyTorch_Project\dataset' ## 데이터셋 경로 설정
CLASSES_LIST = ['fall','Fight'] ## 폴더이름하고 동일한
SEQUENCE_LENGTH = 16
batch_size= 4
x_tensor, y_tensor=Fight_utils.create_dataset(DATASET_DIR,CLASSES_LIST,SEQUENCE_LENGTH)
Extracting Data of Class: fall
Extracting Data of Class: Fight
x_tensor.shape, y_tensor.shape
(torch.Size([40, 3, 16, 112, 112]), torch.Size([40]))
np.unique(y_tensor, return_counts = True)
(array([0, 1], dtype=int64), array([20, 20], dtype=int64))

device 셋팅

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
device
device(type='cpu')

데이터셋 분할

x_tensor, y_tensor = x_tensor.to(device), y_tensor.to(device)

dataset = torch.utils.data.TensorDataset(x_tensor, y_tensor) # 입력 데이터와 해당하는 레이블을 함께 저장

val_size = int(len(dataset)*0.3) ##

train_size = len(dataset)- int(len(dataset)*0.3)
train_dataset, test_val_dataset = torch.utils.data.random_split(dataset, [train_size, val_size])

val_size = int(len(test_val_dataset)*0.5)
test_size = len(test_val_dataset)- int(len(test_val_dataset)*0.5)
val_dataset, test_dataset = torch.utils.data.random_split(test_val_dataset, [val_size, test_size])

train_loader = torch.utils.data.DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
val_loader = torch.utils.data.DataLoader(dataset=val_dataset, batch_size=batch_size, shuffle=True)
dataloaders_dict = {'train':train_loader,'val':val_loader }
# To empty the Memory
torch.cuda.empty_cache()
train_dataset[1][1]
tensor(1)

모델 학습

# 모델 GPU에 올리기
model_ft = model_ft.to(device)

# 에포크 설정
epochs = 5

# Loss Function 설정
criterion = torch.nn.CrossEntropyLoss()

# Optimization Function (SGD-----> Stocastic Gradient Descent)
optimizer_ft = torch.optim.SGD(model_ft.parameters(), lr=0.001, momentum=0.9)
model_ft, hist = Fight_utils.train_model(device,model_ft, dataloaders_dict, criterion, optimizer_ft, num_epochs=epochs)
Epoch 0/4
----------
train Loss: 0.3590 Acc: 0.8214
val Loss: 0.0717 Acc: 1.0000

Epoch 1/4
----------
train Loss: 0.3617 Acc: 0.7857
val Loss: 0.0303 Acc: 1.0000

Epoch 2/4
----------
train Loss: 0.3411 Acc: 0.7143
val Loss: 0.0488 Acc: 1.0000

Epoch 3/4
----------
train Loss: 0.1391 Acc: 1.0000
val Loss: 0.0341 Acc: 1.0000

Epoch 4/4
----------
train Loss: 0.3958 Acc: 0.7500
val Loss: 0.0256 Acc: 1.0000

Training complete in 2m 33s
Best val Acc: 1.000000

test 데이터 예측

since = time.time()
test_loader = torch.utils.data.DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=True) ## test 데이터를 배치단위로 쪼갬

model_ft.eval() ##  평가모드로 전환

running_loss = 0.0 ## loss값 초기
running_corrects = 0
y_test = []
y_pred = []
for inputs, labels in test_loader:
  inputs = inputs.to(device)
  labels = labels.to(device)
  optimizer_ft.zero_grad()
  with torch.set_grad_enabled(False):
    outputs = model_ft(inputs)
    loss = criterion(outputs, labels)
    _, preds = torch.max(outputs, 1)
  running_loss += loss.item() * inputs.size(0)
  running_corrects += torch.sum(preds == labels.data)
  y_test += labels.data.tolist()
  y_pred += preds.data.tolist()

epoch_loss = running_loss / len(test_loader.dataset)
epoch_acc = running_corrects.double() / len(test_loader.dataset)
time_elapsed = time.time() - since
print('완료 시간 : {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))
print('Loss: {:.4f} Acc: {:.4f}'.format(epoch_loss, epoch_acc))
완료 시간 : 0m 2s
Loss: 0.0779 Acc: 1.0000
from sklearn.metrics import *
cf_matrix = confusion_matrix(y_test, y_pred)
print(cf_matrix)
[[1 0]
 [0 5]]
print(classification_report(y_test, y_pred))
              precision    recall  f1-score   support

           0       1.00      1.00      1.00         1
           1       1.00      1.00      1.00         5

    accuracy                           1.00         6
   macro avg       1.00      1.00      1.00         6
weighted avg       1.00      1.00      1.00         6

model save & load & predict

save

PATH = "D:/projects/mysite2/posts/DX/BP/model_save/test_model1.pth"
torch.save(model_ft.state_dict(), PATH)

load

model_ft = torchvision.models.video.mc3_18(pretrained=True, progress=True)

num_ftrs = model_ft.fc.in_features
model_ft.fc = torch.nn.Linear(num_ftrs, 2)
model_ft.load_state_dict(torch.load(PATH))
model_ft = model_ft.to(device)
#model_ft.eval()

predict

원본비디오 재생

os.listdir("D:/projects/mysite2/posts/DX/BP/test video/폭행")
['폭행29.mp4', '폭행30.mp4', '폭행31.mp4', '폭행32.mp4', '폭행33.mp4']
path_output = "D:/projects/mysite2/posts/DX/BP/test video/폭행/폭행31.mp4"
Fight_utils.show_video(path_output, width=960)

비디오 클래스 추정

path_1 = "D:/projects/mysite2/posts/DX/BP/test video/폭행/폭행31.mp4"
path_2 = "D:/projects/mysite2/posts/DX/BP/test video/실신/실신19.mp4"
SEQUENCE_LENGTH=16

- 슈발 함수 수정하고 restart 하니까 된다…

print(Fight_utils.FightInference(path_1,model_ft,SEQUENCE_LENGTH))
print(Fight_utils.FightInference_Time(path_1, model_ft, SEQUENCE_LENGTH)) ## 추론하는데 걸린시간
fight
[('fight', 0.60055), ('fall', 0.39945)]
***********
time is: 2.789564371109009
fight

클래스 추정 후 비디오 표시

import Fight_utils
from Fight_utils import *
output_path = "D:/projects/mysite2/posts/DX/BP/test video/output/result1.mp4"
start_time = time.time()
outVideo_1=Fight_utils.showIference(model_ft, 16, 2, path_1, output_path, showInfo = False)
elapsed = time.time() - start_time
print("time is:",elapsed)
time is: 8.3247389793396
VideoFileClip(outVideo_1, audio=False, target_resolution=(300,None)).ipython_display()
Moviepy - Building video __temp__.mp4.
Moviepy - Writing video __temp__.mp4

Moviepy - Done !
Moviepy - video ready __temp__.mp4